﻿using System;
using System.Collections.Generic;
using System.Text;

namespace ChemicalEquilibrium
{
    /// <summary>
    /// 化合分解平衡反应
    /// </summary>
    public class ReactCombine
    {
        public Queue<Reactant> As, Bs, ABs, AB_s, C_s;
        public int PositiveVelocity, ReverseVelocity; //正, 逆反应速度
        int PositiveParameter, ReverseParameter;
        int PositiveEfficiency, ReverseEfficiency;

        public int GetACount() { return this.As.Count; }
        public int GetBCount() { return this.Bs.Count; }
        public int GetABCount() { return this.ABs.Count; }
        public int GetAB_Count() { return this.AB_s.Count; }
        public int GetC_Count() { return this.C_s.Count; }
        public int GetPositiveVelocity() { return this.PositiveVelocity; }
        public int GetReverseVelocity() { return this.ReverseVelocity; }

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="As">反应物A</param>
        /// <param name="Bs">反应物B</param>
        /// <param name="ABs">化合的AB</param>
        /// <param name="AB_s">分解的AB</param>
        /// <param name="C_s">分解催化剂</param>
        /// <param name="activateParameter">化合速度参数 : [2, 100]</param>
        /// <param name="inactivateParameter">分解速度参数 : [2, 100]</param>
        public ReactCombine(Queue<Reactant> As, Queue<Reactant> Bs, Queue<Reactant> ABs, Queue<Reactant> AB_s, Queue<Reactant> C_s, int positiveParameter, int reverseParameter, int positiveEfficiency, int reverseEfficiency)
        {
            this.As = As;
            this.Bs = Bs;
            this.ABs = ABs;
            this.AB_s = AB_s;
            this.C_s = C_s;
            this.PositiveParameter = positiveParameter;
            this.ReverseParameter = reverseParameter;
            this.PositiveEfficiency = positiveEfficiency;
            this.ReverseEfficiency = reverseEfficiency;

            if (As == null || Bs == null || ABs == null || AB_s == null) throw new Exception("React Error : Reactant is null!");

        }

        //化合
        public void Combine()
        {
            if (As.Count * Bs.Count == 0)
                this.PositiveVelocity = 0;
            else if (As.Count * Bs.Count / (As.Count + Bs.Count) < this.PositiveParameter)
                this.PositiveVelocity = 1;
            else
                this.PositiveVelocity = As.Count * Bs.Count / (As.Count + Bs.Count) / this.PositiveParameter;

            for (int i = 0; i < this.PositiveVelocity; i++)
            {
                if (this.As.Count == 0 || this.Bs.Count == 0
                    || this.AB_s.Count == 0) break;

                Reactant ab = this.AB_s.Dequeue();
                Reactant a = this.As.Dequeue();
                Reactant b = this.Bs.Dequeue();

                if (a != null && b != null && ab != null)
                {
                    ab.Combine(a);
                    ab.Combine(b);
                    this.ABs.Enqueue(ab);
                }
            }
        }

        //分解
        public void Resolve()
        {
            if (this.C_s != null)
            {
                if (this.ABs.Count * this.C_s.Count == 0)
                    this.ReverseVelocity = 0;
                else if (this.ABs.Count * this.C_s.Count * this.ReverseEfficiency / (this.ABs.Count + this.C_s.Count * this.ReverseEfficiency) < this.ReverseParameter)
                    this.ReverseVelocity = Math.Min(this.ABs.Count, this.C_s.Count);
                    //this.ReverseVelocity = this.ABs.Count * this.C_s.Count * this.ReverseEfficiency / (this.ABs.Count + this.C_s.Count * this.ReverseEfficiency);
                else
                    this.ReverseVelocity = this.ABs.Count * this.C_s.Count * this.ReverseEfficiency / (this.ABs.Count + this.C_s.Count * this.ReverseEfficiency) / this.ReverseParameter;
            }
            else
                this.ReverseVelocity = (this.ABs.Count + this.ReverseParameter - 1) / this.ReverseParameter;

            for (int i = 0; i < this.ReverseVelocity; i++)
            {
                if (this.ABs.Count == 0) break;

                Reactant ab = this.ABs.Dequeue();
                Reactant a = ab.Resolve();
                Reactant b = ab.Resolve();

                if (a != null && b != null && ab != null)
                {
                    this.As.Enqueue(a);
                    this.Bs.Enqueue(b);
                    this.AB_s.Enqueue(ab);
                }
                else
                    this.ABs.Enqueue(ab);

            }

        }

    }
}
